﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Validity.Contexts;
using Validity.Rules;

namespace Validity.Test.Contexts
{
  [TestClass]
  public class ConditionalValidationContextTest
  {
    private readonly StubValidationContext<IComparable> _context = new StubValidationContext<IComparable>();
    
    [TestMethod]
    public void TestDefaultCtor()
    {
      Assert.IsNotNull(new ConditionalValidationContext<ObjectStub, IComparable>());
    }

    [TestMethod]
    public void TestIfUsingSimplePredicate()
    {
      Assert.IsNotNull(CreateConditionalValidationContext().If(() => true));
      VerifyDecorateedRule(new ObjectStub(), "Some Value");
    }

    [TestMethod]
    public void TestIfUsingDynamicStringBasedOnValue()
    {
      var expectedValue = String.Empty;
      Assert.IsNotNull(CreateConditionalValidationContext().If((IComparable val) =>
      {
        Assert.AreEqual(expectedValue, val);
        return true;
      }));
      VerifyDecorateedRule(new ObjectStub(), expectedValue);
    }

    [TestMethod]
    public void TestIfUsingDynamicStringBasedOnObject()
    {
      var expectedObject = new ObjectStub();
      Assert.IsNotNull(CreateConditionalValidationContext().If((ObjectStub obj) =>
      {
        Assert.AreEqual(expectedObject, obj);
        return true;
      }));
      VerifyDecorateedRule(expectedObject, "Some Value");
    }

    [TestMethod]
    public void TestIfUsingDynamicStringBasedOnObjectAndValue()
    {
      var expectedObject = new ObjectStub();
      var expectedValue = String.Empty;

      Assert.IsNotNull(CreateConditionalValidationContext().If((obj, val) =>
      {
        Assert.AreEqual(expectedObject, obj);
        Assert.AreEqual(expectedValue, val);
        return true;
      }));

      VerifyDecorateedRule(expectedObject, expectedValue);
    }

    [TestMethod]
    public void TestUnlessUsingSimplePredicate()
    {
      Assert.IsNotNull(CreateConditionalValidationContext().Unless(() => false));
      VerifyDecorateedRule(new ObjectStub(), "Some Value");
    }

    [TestMethod]
    public void TestUnlessUsingDynamicStringBasedOnValue()
    {
      var expectedValue = String.Empty;
      Assert.IsNotNull(CreateConditionalValidationContext().Unless((IComparable val) =>
      {
        Assert.AreEqual(expectedValue, val);
        return false;
      }));
      VerifyDecorateedRule(new ObjectStub(), expectedValue);
    }

    [TestMethod]
    public void TestUnlessUsingDynamicStringBasedOnObject()
    {
      var expectedObject = new ObjectStub();
      Assert.IsNotNull(CreateConditionalValidationContext().Unless((ObjectStub obj) =>
      {
        Assert.AreEqual(expectedObject, obj);
        return false;
      }));
      VerifyDecorateedRule(expectedObject, "Some Value");
    }

    [TestMethod]
    public void TestUnlessUsingDynamicStringBasedOnObjectAndValue()
    {
      var expectedObject = new ObjectStub();
      var expectedValue = String.Empty;

      Assert.IsNotNull(CreateConditionalValidationContext().Unless((obj, val) =>
      {
        Assert.AreEqual(expectedObject, obj);
        Assert.AreEqual(expectedValue, val);
        return true;
      }));

      VerifyDecorateedRule(expectedObject, expectedValue);
    }

    private ConditionalValidationContext<ObjectStub, IComparable> CreateConditionalValidationContext()
    {
      var context = new ConditionalValidationContext<ObjectStub, IComparable>(_context);
      var rule = new Rule<ObjectStub, IComparable>((obj, val) => true, (obj, val) => "Original Message");

      _context.Rule.Add(rule);

      return context;
    }

    private void VerifyDecorateedRule(ObjectStub obj, IComparable value)
    {
      IRule<ObjectStub, IComparable> rule = _context.Rule[0];

      Assert.IsFalse(rule.IsViolatedBy(obj, value));
    }
  }
}
